﻿
namespace Anycmd.Host.AC.MemorySets.Impl
{
    using AC.Infra;
    using Anycmd.AC.Infra;
    using Anycmd.Bus;
    using Exceptions;
    using Extensions;
    using Host;
    using Host.Impl;
    using Infra.Messages;
    using Repositories;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using InOuts;

    public sealed class UIViewSet : IUIViewSet
    {
        public static readonly IUIViewSet Empty = new UIViewSet(EmptyACDomain.SingleInstance);

        private readonly Dictionary<FunctionState, UIViewState> _viewDicByFunction = new Dictionary<FunctionState, UIViewState>();
        private readonly Dictionary<Guid, UIViewState> _viewDicByID = new Dictionary<Guid, UIViewState>();
        private bool _initialized = false;

        private readonly Guid _id = Guid.NewGuid();
        private readonly IACDomain host;
        private readonly UIViewButtonSet viewButtonSet;

        public Guid Id
        {
            get { return _id; }
        }

        public UIViewSet(IACDomain host)
        {
            if (host == null)
            {
                throw new ArgumentNullException("host");
            }
            this.host = host;
            viewButtonSet = new UIViewButtonSet(host);
            new MessageHandler(this).Register();
        }

        public bool TryGetUIView(FunctionState function, out UIViewState view)
        {
            if (!_initialized)
            {
                Init();
            }

            return _viewDicByFunction.TryGetValue(function, out view);
        }

        public bool TryGetUIView(Guid viewID, out UIViewState view)
        {
            if (!_initialized)
            {
                Init();
            }
            return _viewDicByID.TryGetValue(viewID, out view);
        }

        public IReadOnlyList<UIViewButtonState> GetUIViewButtons(UIViewState view)
        {
            if (!_initialized)
            {
                Init();
            }
            return viewButtonSet.GetUIViewButtons(view);
        }

        public IEnumerable<UIViewButtonState> GetUIViewButtons()
        {
            if (!_initialized)
            {
                Init();
            }
            return viewButtonSet;
        }

        internal void Refresh()
        {
            if (_initialized)
            {
                _initialized = false;
            }
        }

        public IEnumerator<UIViewState> GetEnumerator()
        {
            if (!_initialized)
            {
                Init();
            }
            return _viewDicByID.Values.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            if (!_initialized)
            {
                Init();
            }
            return _viewDicByID.Values.GetEnumerator();
        }

        private void Init()
        {
            if (!_initialized)
            {
                lock (this)
                {
                    if (!_initialized)
                    {
                        _viewDicByFunction.Clear();
                        _viewDicByID.Clear();
                        var views = host.GetRequiredService<IOriginalHostStateReader>().GetAllUIViews();
                        foreach (var view in views)
                        {
                            if (!(view is UIViewBase))
                            {
                                throw new CoreException(view.GetType().Name + "必须继承" + typeof(UIViewBase).Name);
                            }
                            var viewState = UIViewState.Create(host, view);
                            _viewDicByID.Add(view.Id, viewState);
                            FunctionState function;
                            if (!host.FunctionSet.TryGetFunction(view.Id, out function))
                            {
                                throw new NotExistException("意外的功能标识" + view.Id);
                            }
                            if (!_viewDicByFunction.ContainsKey(function))
                            {
                                _viewDicByFunction.Add(function, viewState);
                            }
                        }
                        _initialized = true;
                    }
                }
            }
        }

        #region MessageHandler
        private class MessageHandler:
            IHandler<AddUIViewCommand>,
            IHandler<UIViewUpdatedEvent>,
            IHandler<RemoveUIViewCommand>,
            IHandler<FunctionUpdatedEvent>,
            IHandler<FunctionRemovingEvent>,
            IHandler<FunctionRemovedEvent>, 
            IHandler<UIViewAddedEvent>, 
            IHandler<UpdateUIViewCommand>, 
            IHandler<UIViewRemovedEvent>
        {
            private readonly UIViewSet set;

            public MessageHandler(UIViewSet set)
            {
                this.set = set;
            }

            public void Register()
            {
                var messageDispatcher = set.host.MessageDispatcher;
                if (messageDispatcher == null)
                {
                    throw new ArgumentNullException("messageDispatcher has not be set of host:{0}".Fmt(set.host.Name));
                }
                messageDispatcher.Register((IHandler<AddUIViewCommand>)this);
                messageDispatcher.Register((IHandler<UIViewAddedEvent>)this);
                messageDispatcher.Register((IHandler<UpdateUIViewCommand>)this);
                messageDispatcher.Register((IHandler<UIViewUpdatedEvent>)this);
                messageDispatcher.Register((IHandler<RemoveUIViewCommand>)this);
                messageDispatcher.Register((IHandler<UIViewRemovedEvent>)this);
                messageDispatcher.Register((IHandler<FunctionUpdatedEvent>)this);
                messageDispatcher.Register((IHandler<FunctionRemovingEvent>)this);
                messageDispatcher.Register((IHandler<FunctionRemovedEvent>)this);
            }

            public void Handle(FunctionUpdatedEvent message)
            {
                var host = set.host;
                var _viewDicByFunction = set._viewDicByFunction;
                FunctionState newKey;
                if (!host.FunctionSet.TryGetFunction(message.Source.Id, out newKey))
                {
                    throw new CoreException("意外的功能标识" + message.Source.Id);
                }
                var oldKey = _viewDicByFunction.Keys.FirstOrDefault(a => a.Id == newKey.Id);
                if (oldKey != null && !_viewDicByFunction.ContainsKey(newKey))
                {
                    _viewDicByFunction.Add(newKey, _viewDicByFunction[oldKey]);
                    _viewDicByFunction.Remove(oldKey);
                }
            }

            public void Handle(FunctionRemovingEvent message)
            {
                var host = set.host;
                var _viewDicByFunction = set._viewDicByFunction;
                var _viewDicByID = set._viewDicByID;
                if (_viewDicByID.ContainsKey(message.Source.Id))
                {
                    host.Handle(new RemoveUIViewCommand(message.Source.Id));
                }
            }

            public void Handle(FunctionRemovedEvent message)
            {
                var host = set.host;
                var _viewDicByFunction = set._viewDicByFunction;
                var _viewDicByID = set._viewDicByID;
                var key = _viewDicByFunction.Keys.FirstOrDefault(a => a.Id == message.Source.Id);
                if (key != null)
                {
                    _viewDicByFunction.Remove(key);
                }
            }

            public void Handle(AddUIViewCommand message)
            {
                this.Handle(message.Input, true);
            }

            public void Handle(UIViewAddedEvent message)
            {
                if (message.GetType() == typeof(PrivateUIViewAddedEvent))
                {
                    return;
                }
                this.Handle(message.Output, false);
            }

            private void Handle(IUIViewCreateIO input, bool isCommand)
            {
                var host = set.host;
                var _viewDicByFunction = set._viewDicByFunction;
                var _viewDicByID = set._viewDicByID;
                var viewRepository = host.GetRequiredService<IRepository<UIView>>();
                if (!input.Id.HasValue)
                {
                    throw new ValidationException("标识是必须的");
                }
                UIView entity;
                lock (this)
                {
                    FunctionState function;
                    if (!host.FunctionSet.TryGetFunction(input.Id.Value, out function))
                    {
                        throw new ValidationException("意外的功能标识，界面视图首先是个功能。请先添加界面视图对应的功能记录。");
                    }
                    UIViewState view;
                    if (host.UIViewSet.TryGetUIView(input.Id.Value, out view))
                    {
                        throw new ValidationException("给定标识的界面视图已经存在");
                    }

                    entity = UIView.Create(input);

                    var state = UIViewState.Create(host, entity);
                    if (!_viewDicByID.ContainsKey(state.Id))
                    {
                        _viewDicByID.Add(state.Id, state);
                    }
                    if (!_viewDicByFunction.ContainsKey(function))
                    {
                        _viewDicByFunction.Add(function, state);
                    }
                    if (isCommand)
                    {
                        try
                        {
                            viewRepository.Add(entity);
                            viewRepository.Context.Commit();
                        }
                        catch
                        {
                            if (_viewDicByID.ContainsKey(entity.Id))
                            {
                                _viewDicByID.Remove(entity.Id);
                            }
                            if (_viewDicByFunction.ContainsKey(function))
                            {
                                _viewDicByFunction.Remove(function);
                            }
                            viewRepository.Context.Rollback();
                            throw;
                        }
                    }
                }
                if (isCommand)
                {
                    host.MessageDispatcher.DispatchMessage(new PrivateUIViewAddedEvent(entity, input));
                }
            }

            private class PrivateUIViewAddedEvent : UIViewAddedEvent
            {
                public PrivateUIViewAddedEvent(UIViewBase source, IUIViewCreateIO input)
                    : base(source, input)
                {

                }
            }
            public void Handle(UpdateUIViewCommand message)
            {
                this.Handle(message.Output, true);
            }

            public void Handle(UIViewUpdatedEvent message)
            {
                if (message.GetType() == typeof(PrivateUIViewUpdatedEvent))
                {
                    return;
                }
                this.Handle(message.Input, false);
            }

            private void Handle(IUIViewUpdateIO input, bool isCommand)
            {
                var host = set.host;
                var _viewDicByFunction = set._viewDicByFunction;
                var _viewDicByID = set._viewDicByID;
                var viewRepository = host.GetRequiredService<IRepository<UIView>>();
                UIViewState bkState;
                if (!host.UIViewSet.TryGetUIView(input.Id, out bkState))
                {
                    throw new NotExistException();
                }
                UIView entity;
                bool stateChanged = false;
                lock (bkState)
                {
                    UIViewState state;
                    if (!host.UIViewSet.TryGetUIView(input.Id, out state))
                    {
                        throw new NotExistException();
                    }
                    entity = viewRepository.GetByKey(input.Id);
                    if (entity == null)
                    {
                        throw new NotExistException();
                    }

                    entity.Update(input);

                    var newState = UIViewState.Create(host, entity);
                    stateChanged = newState != bkState;
                    if (stateChanged)
                    {
                        Update(newState);
                    }
                    if (isCommand)
                    {
                        try
                        {
                            viewRepository.Update(entity);
                            viewRepository.Context.Commit();
                        }
                        catch
                        {
                            if (stateChanged)
                            {
                                Update(bkState);
                            }
                            viewRepository.Context.Rollback();
                            throw;
                        }
                    }
                }
                if (isCommand && stateChanged)
                {
                    host.MessageDispatcher.DispatchMessage(new PrivateUIViewUpdatedEvent(entity, input));
                }
            }

            private void Update(UIViewState state)
            {
                var host = set.host;
                var _viewDicByFunction = set._viewDicByFunction;
                var _viewDicByID = set._viewDicByID;
                FunctionState function;
                host.FunctionSet.TryGetFunction(state.Id, out function);
                _viewDicByID[state.Id] = state;
                _viewDicByFunction[function] = state;
            }

            private class PrivateUIViewUpdatedEvent : UIViewUpdatedEvent
            {
                public PrivateUIViewUpdatedEvent(UIViewBase source, IUIViewUpdateIO input)
                    : base(source, input)
                {

                }
            }
            public void Handle(RemoveUIViewCommand message)
            {
                this.Handle(message.EntityID, true);
            }

            public void Handle(UIViewRemovedEvent message)
            {
                if (message.GetType() == typeof(PrivateUIViewRemovedEvent))
                {
                    return;
                }
                this.Handle(message.Source.Id, false);
            }

            private void Handle(Guid viewID, bool isCommand)
            {
                var host = set.host;
                var _viewDicByFunction = set._viewDicByFunction;
                var _viewDicByID = set._viewDicByID;
                var viewRepository = host.GetRequiredService<IRepository<UIView>>();
                var viewButtonRepository = host.GetRequiredService<IRepository<UIViewButton>>();
                UIViewState bkState;
                if (!host.UIViewSet.TryGetUIView(viewID, out bkState))
                {
                    return;
                }
                UIView entity;
                lock (bkState)
                {
                    UIViewState state;
                    if (!host.UIViewSet.TryGetUIView(viewID, out state))
                    {
                        return;
                    }
                    FunctionState function;
                    if (!host.FunctionSet.TryGetFunction(viewID, out function))
                    {
                        throw new NotExistException("意外的功能标识" + viewID);
                    }
                    entity = viewRepository.GetByKey(viewID);
                    if (entity == null)
                    {
                        return;
                    }
                    foreach (var viewButton in viewButtonRepository.AsQueryable().Where(a => a.UIViewID == entity.Id).ToList())
                    {
                        viewButtonRepository.Remove(viewButton);
                    }
                    if (_viewDicByID.ContainsKey(bkState.Id))
                    {
                        if (isCommand)
                        {
                            host.MessageDispatcher.DispatchMessage(new UIViewRemovingEvent(entity));
                        }
                        _viewDicByID.Remove(bkState.Id);
                    }
                    if (_viewDicByFunction.ContainsKey(function))
                    {
                        _viewDicByFunction.Remove(function);
                    }
                    if (isCommand)
                    {
                        try
                        {
                            viewButtonRepository.Context.Commit();
                            viewRepository.Remove(entity);
                            viewRepository.Context.Commit();
                        }
                        catch
                        {
                            if (!_viewDicByID.ContainsKey(bkState.Id))
                            {
                                _viewDicByID.Add(bkState.Id, bkState);
                            }
                            if (!_viewDicByFunction.ContainsKey(function))
                            {
                                _viewDicByFunction.Add(function, bkState);
                            }
                            viewButtonRepository.Context.Rollback();
                            viewRepository.Context.Rollback();
                            throw;
                        }
                    }
                }
                if (isCommand)
                {
                    host.MessageDispatcher.DispatchMessage(new PrivateUIViewRemovedEvent(entity));
                }
            }

            private class PrivateUIViewRemovedEvent : UIViewRemovedEvent
            {
                public PrivateUIViewRemovedEvent(UIViewBase source)
                    : base(source)
                {

                }
            }
        }
        #endregion

        // 内部类
        #region UIViewButtonSet
        /// <summary>
        /// 界面视图菜单上下文
        /// </summary>
        private sealed class UIViewButtonSet : IEnumerable<UIViewButtonState>
        {
            private readonly Dictionary<UIViewState, List<UIViewButtonState>> _viewButtonsByUIView = new Dictionary<UIViewState, List<UIViewButtonState>>();
            private readonly Dictionary<Guid, UIViewButtonState> _viewButtonDicByID = new Dictionary<Guid, UIViewButtonState>();
            private bool _initialized = false;
            private readonly IACDomain host;

            public UIViewButtonSet(IACDomain host)
            {
                this.host = host;
                new MessageHandler(this).Register();
            }

            public IReadOnlyList<UIViewButtonState> GetUIViewButtons(UIViewState view)
            {
                if (!_initialized)
                {
                    Init();
                }
                if (!_viewButtonsByUIView.ContainsKey(view))
                {
                    return new List<UIViewButtonState>();
                }

                return _viewButtonsByUIView[view];
            }

            public IEnumerator<UIViewButtonState> GetEnumerator()
            {
                if (!_initialized)
                {
                    Init();
                }
                foreach (var item in _viewButtonDicByID.Values)
                {
                    yield return item;
                }
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                if (!_initialized)
                {
                    Init();
                }
                foreach (var item in _viewButtonDicByID.Values)
                {
                    yield return item;
                }
            }

            private void Init()
            {
                if (!_initialized)
                {
                    lock (this)
                    {
                        if (!_initialized)
                        {
                            _viewButtonsByUIView.Clear();
                            _viewButtonDicByID.Clear();
                            var allUIViewButtons = host.GetRequiredService<IOriginalHostStateReader>().GetAllUIViewButtons();
                            foreach (var viewButton in allUIViewButtons)
                            {
                                if (!(viewButton is UIViewButtonBase))
                                {
                                    throw new CoreException(viewButton.GetType().Name + "必须继承" + typeof(UIViewButtonBase).Name);
                                }
                                var viewButtonState = UIViewButtonState.Create(host, viewButton);
                                if (!_viewButtonDicByID.ContainsKey(viewButton.Id))
                                {
                                    _viewButtonDicByID.Add(viewButton.Id, viewButtonState);
                                }
                                if (!_viewButtonsByUIView.ContainsKey(viewButtonState.UIView))
                                {
                                    _viewButtonsByUIView.Add(viewButtonState.UIView, new List<UIViewButtonState>());
                                }
                                _viewButtonsByUIView[viewButtonState.UIView].Add(viewButtonState);
                            }
                            foreach (var item in _viewButtonsByUIView)
                            {
                                item.Value.Sort(new UIViewButtonCompare());
                            }
                            _initialized = true;
                        }
                    }
                }
            }

            #region MessageHandler
            private class MessageHandler:
                IHandler<UIViewButtonAddedEvent>,
                IHandler<UIViewButtonUpdatedEvent>,
                IHandler<RemoveUIViewButtonCommand>,
                IHandler<UIViewButtonRemovedEvent>,
                IHandler<UIViewUpdatedEvent>,
                IHandler<FunctionRemovingEvent>,
                IHandler<AddUIViewButtonCommand>,
                IHandler<UpdateUIViewButtonCommand>,
                IHandler<UIViewRemovingEvent>,
                IHandler<UIViewRemovedEvent>
            {
                private readonly UIViewButtonSet set;

                public MessageHandler(UIViewButtonSet set)
                {
                    this.set = set;
                }

                public void Register()
                {
                    var messageDispatcher = set.host.MessageDispatcher;
                    if (messageDispatcher == null)
                    {
                        throw new ArgumentNullException("messageDispatcher has not be set of host:{0}".Fmt(set.host.Name));
                    }
                    messageDispatcher.Register((IHandler<AddUIViewButtonCommand>)this);
                    messageDispatcher.Register((IHandler<UIViewButtonAddedEvent>)this);
                    messageDispatcher.Register((IHandler<UpdateUIViewButtonCommand>)this);
                    messageDispatcher.Register((IHandler<UIViewButtonUpdatedEvent>)this);
                    messageDispatcher.Register((IHandler<RemoveUIViewButtonCommand>)this);
                    messageDispatcher.Register((IHandler<UIViewButtonRemovedEvent>)this);
                    messageDispatcher.Register((IHandler<UIViewUpdatedEvent>)this);
                    messageDispatcher.Register((IHandler<UIViewRemovingEvent>)this);
                    messageDispatcher.Register((IHandler<UIViewRemovedEvent>)this);
                    messageDispatcher.Register((IHandler<FunctionRemovingEvent>)this);
                }

                public void Handle(UIViewUpdatedEvent message)
                {
                    var host = set.host;
                    var _viewButtonsByUIView = set._viewButtonsByUIView;
                    UIViewState newKey;
                    if (!host.UIViewSet.TryGetUIView(message.Source.Id, out newKey))
                    {
                        throw new CoreException("意外的界面视图标识" + message.Source.Id);
                    }
                    var oldKey = _viewButtonsByUIView.Keys.FirstOrDefault(a => a.Id == newKey.Id);
                    if (oldKey != null && !_viewButtonsByUIView.ContainsKey(newKey))
                    {
                        _viewButtonsByUIView.Add(newKey, _viewButtonsByUIView[oldKey]);
                        _viewButtonsByUIView.Remove(oldKey);
                    }
                }

                public void Handle(UIViewRemovingEvent message)
                {
                    var host = set.host;
                    var _viewButtonsByUIView = set._viewButtonsByUIView;
                    UIViewState key;
                    if (!host.UIViewSet.TryGetUIView(message.Source.Id, out key))
                    {
                        throw new CoreException("意外的界面视图标识" + message.Source.Id);
                    }
                    if (_viewButtonsByUIView.ContainsKey(key))
                    {
                        HashSet<Guid> viewButtonIDs = new HashSet<Guid>();
                        foreach (var item in _viewButtonsByUIView[key])
                        {
                            viewButtonIDs.Add(item.Id);
                        }
                        foreach (var viewButtonID in viewButtonIDs)
                        {
                            host.Handle(new RemoveUIViewButtonCommand(viewButtonID));
                        }
                        _viewButtonsByUIView.Remove(key);
                    }
                }

                public void Handle(UIViewRemovedEvent message)
                {
                    var host = set.host;
                    var _viewButtonsByUIView = set._viewButtonsByUIView;
                    var key = _viewButtonsByUIView.Keys.FirstOrDefault(a => a.Id == message.Source.Id);
                    if (key != null)
                    {
                        _viewButtonsByUIView.Remove(key);
                    }
                }

                public void Handle(FunctionRemovingEvent message)
                {
                    var host = set.host;
                    var _viewButtonsByUIView = set._viewButtonsByUIView;
                    var _viewButtonDicByID = set._viewButtonDicByID;
                    HashSet<Guid> viewButtonIDs = new HashSet<Guid>();
                    foreach (var item in _viewButtonDicByID.Values)
                    {
                        if (item.FunctionID.HasValue && item.FunctionID.Value == message.Source.Id)
                        {
                            viewButtonIDs.Add(item.Id);
                        }
                    }
                    foreach (var viewButtonID in viewButtonIDs)
                    {
                        host.Handle(new RemoveUIViewButtonCommand(viewButtonID));
                    }
                }

                public void Handle(AddUIViewButtonCommand message)
                {
                    this.Handle(message.Input, true);
                }

                public void Handle(UIViewButtonAddedEvent message)
                {
                    if (message.GetType() == typeof(PrivateUIViewButtonAddedEvent))
                    {
                        return;
                    }
                    this.Handle(message.Output, false);
                }

                private void Handle(IUIViewButtonCreateIO input, bool isCommand)
                {
                    var host = set.host;
                    var _viewButtonsByUIView = set._viewButtonsByUIView;
                    var _viewButtonDicByID = set._viewButtonDicByID;
                    var viewButtonRepository = host.GetRequiredService<IRepository<UIViewButton>>();
                    if (!input.Id.HasValue)
                    {
                        throw new ValidationException("标识是必须的");
                    }
                    UIViewButton entity;
                    lock (this)
                    {
                        ButtonState button;
                        if (!host.ButtonSet.TryGetButton(input.ButtonID, out button))
                        {
                            throw new ValidationException("按钮不存在");
                        }
                        UIViewState view;
                        if (!host.UIViewSet.TryGetUIView(input.UIViewID, out view))
                        {
                            throw new ValidationException("界面视图不存在");
                        }
                        if (input.FunctionID.HasValue)
                        {
                            FunctionState function;
                            if (!host.FunctionSet.TryGetFunction(input.FunctionID.Value, out function))
                            {
                                throw new ValidationException("托管功能不存在");
                            }
                        }
                        if (host.UIViewSet.GetUIViewButtons().Any(a => a.Id == input.Id.Value))
                        {
                            throw new ValidationException("给定标识的界面视图按钮已经存在");
                        }

                        entity = UIViewButton.Create(input);

                        var state = UIViewButtonState.Create(host, entity);
                        if (!_viewButtonsByUIView.ContainsKey(view))
                        {
                            _viewButtonsByUIView.Add(view, new List<UIViewButtonState>());
                        }
                        if (!_viewButtonsByUIView[view].Contains(state))
                        {
                            _viewButtonsByUIView[view].Add(state);
                        }
                        if (!_viewButtonDicByID.ContainsKey(state.Id))
                        {
                            _viewButtonDicByID.Add(state.Id, state);
                        }
                        if (isCommand)
                        {
                            try
                            {
                                viewButtonRepository.Add(entity);
                                viewButtonRepository.Context.Commit();
                            }
                            catch
                            {
                                if (_viewButtonsByUIView.ContainsKey(view))
                                {
                                    if (_viewButtonsByUIView[view].Any(a => a.Id == entity.Id))
                                    {
                                        var item = _viewButtonsByUIView[view].First(a => a.Id == entity.Id);
                                        _viewButtonsByUIView[view].Remove(item);
                                    }
                                }
                                if (_viewButtonDicByID.ContainsKey(entity.Id))
                                {
                                    _viewButtonDicByID.Remove(entity.Id);
                                }
                                viewButtonRepository.Context.Rollback();
                                throw;
                            }
                        }
                    }
                    if (isCommand)
                    {
                        host.MessageDispatcher.DispatchMessage(new PrivateUIViewButtonAddedEvent(entity, input));
                    }
                }

                private class PrivateUIViewButtonAddedEvent : UIViewButtonAddedEvent
                {
                    public PrivateUIViewButtonAddedEvent(UIViewButtonBase source, IUIViewButtonCreateIO input) : base(source, input) { }
                }
                public void Handle(UpdateUIViewButtonCommand message)
                {
                    this.Handle(message.Output, true);
                }

                public void Handle(UIViewButtonUpdatedEvent message)
                {
                    if (message.GetType() == typeof(PrivateUIViewButtonUpdatedEvent))
                    {
                        return;
                    }
                    this.Handle(message.Input, false);
                }

                private void Update(UIViewButtonState state)
                {
                    var host = set.host;
                    var _viewButtonsByUIView = set._viewButtonsByUIView;
                    var _viewButtonDicByID = set._viewButtonDicByID;
                    var oldState = _viewButtonDicByID[state.Id];
                    _viewButtonDicByID[state.Id] = state;
                    foreach (var item in _viewButtonsByUIView)
                    {
                        if (item.Value.Contains(oldState))
                        {
                            item.Value.Remove(oldState);
                            item.Value.Add(state);
                        }
                    }
                }

                private void Handle(IUIViewButtonUpdateIO input, bool isCommand)
                {
                    var host = set.host;
                    var _viewButtonsByUIView = set._viewButtonsByUIView;
                    var _viewButtonDicByID = set._viewButtonDicByID;
                    var viewButtonRepository = host.GetRequiredService<IRepository<UIViewButton>>();
                    var bkState = host.UIViewSet.GetUIViewButtons().FirstOrDefault(a => a.Id == input.Id);
                    if (bkState == null)
                    {
                        throw new NotExistException();
                    }
                    if (input.FunctionID.HasValue)
                    {
                        FunctionState function;
                        if (!host.FunctionSet.TryGetFunction(input.FunctionID.Value, out function))
                        {
                            throw new ValidationException("非法的托管功能标识" + input.FunctionID);
                        }
                    }
                    UIViewButton entity;
                    bool stateChanged = false;
                    lock (bkState)
                    {
                        if (!host.UIViewSet.GetUIViewButtons().Any(a => a.Id == input.Id))
                        {
                            throw new NotExistException();
                        }
                        entity = viewButtonRepository.GetByKey(input.Id);
                        if (entity == null)
                        {
                            throw new NotExistException();
                        }

                        entity.Update(input);

                        var newState = UIViewButtonState.Create(host, entity);
                        stateChanged = newState != bkState;
                        if (stateChanged)
                        {
                            Update(newState);
                        }
                        if (isCommand)
                        {
                            try
                            {
                                viewButtonRepository.Update(entity);
                                viewButtonRepository.Context.Commit();
                            }
                            catch
                            {
                                if (stateChanged)
                                {
                                    Update(bkState);
                                }
                                viewButtonRepository.Context.Rollback();
                                throw;
                            }
                        }
                    }
                    if (isCommand && stateChanged)
                    {
                        host.MessageDispatcher.DispatchMessage(new PrivateUIViewButtonUpdatedEvent(entity, input));
                    }
                }

                private class PrivateUIViewButtonUpdatedEvent : UIViewButtonUpdatedEvent
                {
                    public PrivateUIViewButtonUpdatedEvent(UIViewButtonBase source, IUIViewButtonUpdateIO input)
                        : base(source, input)
                    {

                    }
                }
                public void Handle(RemoveUIViewButtonCommand message)
                {
                    this.Handle(message.EntityID, true);
                }

                public void Handle(UIViewButtonRemovedEvent message)
                {
                    if (message.GetType() == typeof(PrivateUIViewButtonRemovedEvent))
                    {
                        return;
                    }
                    this.Handle(message.Source.Id, false);
                }

                private void Handle(Guid viewButtonID, bool isCommand)
                {
                    var host = set.host;
                    var _viewButtonsByUIView = set._viewButtonsByUIView;
                    var _viewButtonDicByID = set._viewButtonDicByID;
                    var viewButtonRepository = host.GetRequiredService<IRepository<UIViewButton>>();
                    var bkState = host.UIViewSet.GetUIViewButtons().FirstOrDefault(a => a.Id == viewButtonID);
                    if (bkState == null)
                    {
                        return;
                    }
                    UIViewButton entity;
                    lock (bkState)
                    {
                        if (!host.UIViewSet.GetUIViewButtons().Any(a => a.Id == viewButtonID))
                        {
                            return;
                        }
                        entity = viewButtonRepository.GetByKey(viewButtonID);
                        if (entity == null)
                        {
                            return;
                        }
                        if (_viewButtonDicByID.ContainsKey(bkState.Id))
                        {
                            if (_viewButtonsByUIView.ContainsKey(bkState.UIView) && _viewButtonsByUIView[bkState.UIView].Any(a => a.Id == bkState.Id))
                            {
                                var item = _viewButtonsByUIView[bkState.UIView].First(a => a.Id == bkState.Id);
                                _viewButtonsByUIView[bkState.UIView].Remove(item);
                            }
                            _viewButtonDicByID.Remove(bkState.Id);
                        }
                        if (isCommand)
                        {
                            try
                            {
                                viewButtonRepository.Remove(entity);
                                viewButtonRepository.Context.Commit();
                            }
                            catch
                            {
                                if (!_viewButtonDicByID.ContainsKey(bkState.Id))
                                {
                                    if (!_viewButtonsByUIView.ContainsKey(bkState.UIView))
                                    {
                                        _viewButtonsByUIView.Add(bkState.UIView, new List<UIViewButtonState>());
                                    }
                                    if (!_viewButtonsByUIView[bkState.UIView].Any(a => a.Id == bkState.Id))
                                    {
                                        _viewButtonsByUIView[bkState.UIView].Add(bkState);
                                    }
                                    _viewButtonDicByID.Add(bkState.Id, bkState);
                                }
                                viewButtonRepository.Context.Rollback();
                                throw;
                            }
                        }
                    }
                    if (isCommand)
                    {
                        host.MessageDispatcher.DispatchMessage(new PrivateUIViewButtonRemovedEvent(entity));
                    }
                }

                private class PrivateUIViewButtonRemovedEvent : UIViewButtonRemovedEvent
                {
                    public PrivateUIViewButtonRemovedEvent(UIViewButtonBase source)
                        : base(source)
                    {

                    }
                }
            }
            #endregion

            private class UIViewButtonCompare : IComparer<UIViewButtonState>
            {
                public int Compare(UIViewButtonState x, UIViewButtonState y)
                {
                    return x.Button.SortCode.CompareTo(y.Button.SortCode);
                }
            }
        }
        #endregion
    }
}